home *** CD-ROM | disk | FTP | other *** search
- /* ANSI escape sequence interpreter */
- /* $Header: vtansi.c,v 1.6 88/06/20 22:38:12 guido Exp $ */
-
- /* There is some ugly code here, since I assume that code looking
- at the input a character at a time is very time-critical.
- Action functions are called with the start of the text to process,
- and return a pointer to where they left off.
- When an action function hits the end of the string,
- it returns NULL and sets the action pointer to the function to
- call next (often itself), or to NULL for the default.
- A non-NULL return implies that the default action function must
- be called next and the action pointer is irrelevant.
- Remember that the general form of most ANSI escape sequences is
- ESC [ <n1> ; <n2> ; ... <c>
- where <c> is the command code and <n1>, <n2> etc. are optional
- numerical parameters.
- */
-
- #include "vtimpl.h"
-
- /* Function prototypes */
-
- STATIC char *def_action ARGS((VT *vt, char *text, char *end));
- STATIC char *esc_action ARGS((VT *vt, char *text, char *end));
- STATIC char *ansi_params ARGS((VT *vt, char *text, char *end));
- STATIC char *ansi_execute ARGS((VT *vt, char *text));
- STATIC void vtsetoptions ARGS((VT *vt, bool flag));
- STATIC void vtsetattrlist ARGS((VT *vt));
-
- /* Output a string, interpreting ANSI escapes */
-
- void
- vtansiputs(vt, text, len)
- VT *vt;
- char *text;
- int len;
- {
- char *end;
-
- if (len < 0)
- len= (int)strlen(text);
- end= text + len;
-
- /* Pick up where the last call left us behind */
-
- if (vt->action != NULL)
- text= (*vt->action)(vt, text, end);
-
- /* Start in default state until text exhausted */
-
- while(text != NULL)
- text= def_action(vt, text, end);
-
- /* Execute delayed scrolling */
-
- vtsync(vt);
- }
-
- /* Default action function */
-
- static char *
- def_action(vt, text, end)
- VT *vt;
- char *text, *end;
- {
- again:
- for (;;) {
- if (text >= end) {
- vt->action= NULL;
- return NULL;
- }
- if (PRINTABLE(*text))
- break;
- switch (*text++) {
-
- case ESC: /* ESC */
- return esc_action(vt, text, end);
-
- case BEL: /* Bell */
- wfleep();
- break;
-
- case BS: /* Backspace -- move 1 left */
- /* Rely on vtsetcursor's clipping */
- vtsetcursor(vt, vt->cur_row, vt->cur_col - 1);
- /* Don't erase --
- that's part of intelligent echoing */
- break;
-
- case TAB: /* Tab -- move to next tab stop */
- /* Rely on vtsetcursor's clipping */
- /* TO DO: use programmable tab stops! */
- vtsetcursor(vt, vt->cur_row,
- (vt->cur_col & ~7) + 8);
- /* Normalize cursor (may cause scroll!) */
- vtputstring(vt, "", 0);
- break;
-
- case LF: /* Linefeed -- move down one line */
- if (vt->nlcr)
- vtsetcursor(vt, vt->cur_row, 0);
- vtlinefeed(vt, 1);
- break;
-
- case FF: /* Formfeed */
- /* vtreset(vt); */
- break;
-
- case CR: /* Return -- to col 0 on same line */
- vtsetcursor(vt, vt->cur_row, 0);
- break;
-
- default:
- FAIL();
- break;
- }
- }
-
- /* We fall through the previous loop when we get a printable
- character */
-
- {
- char *p= text;
-
- while (PRINTABLE(*++p)) {
- /* At least one character guaranteed! */
- if (p >= end)
- break;
- }
- vtputstring(vt, text, (int)(p-text));
- text= p;
- goto again;
- }
- }
-
- /* Action function called after ESC seen */
-
- static char *
- esc_action(vt, text, end)
- VT *vt;
- char *text, *end;
- {
- if (text >= end) {
- vt->action= esc_action;
- return NULL;
- }
- switch (*text++) {
- /*
- case '(':
- case ')':
- case '*':
- case '+':
- return cset_action(vt, text, end);
- */
- case '=':
- vt->keypadmode= TRUE;
- break;
- case '>':
- vt->keypadmode= FALSE;
- break;
- case '7':
- vtsavecursor(vt);
- break;
- case '8':
- vtrestorecursor(vt);
- break;
- case 'D':
- vtlinefeed(vt, 1);
- break;
- case 'E':
- /* Next Line */
- break;
- case 'H':
- /* Tab set */
- break;
- case 'M':
- vtrevlinefeed(vt, 1);
- break;
- case '[':
- vt->nextarg= vt->args;
- *vt->nextarg= -1;
- vt->modarg= FALSE;
- return ansi_params(vt, text, end);
- case 'c':
- vtreset(vt);
- break;
- default:
- FAIL();
- break;
- }
- return text;
- }
-
- /* Action function called after ESC-[ plus possible parameters seen */
-
- static char *
- ansi_params(vt, text, end)
- VT *vt;
- char *text, *end;
- {
- again:
- if (text >= end) {
- vt->action= ansi_params;
- return NULL;
- }
- if (isdigit(*text)) {
- long a= *vt->nextarg;
- if (a < 0)
- a= 0;
- do {
- a= a*10 + (*text - '0');
- CLIPMAX(a, 0x7fff); /* Avoid overflow */
- } while (++text < end && isdigit(*text));
- *vt->nextarg= a;
- if (text >= end)
- goto again;
- }
- switch (*text) {
-
- case ';':
- ++text;
- if (vt->nextarg < &vt->args[VTNARGS-1])
- ++vt->nextarg;
- *vt->nextarg= -1;
- goto again;
-
- case '?':
- ++text;
- if (vt->nextarg == vt->args &&
- *vt->nextarg < 0 && !vt->modarg) {
- vt->modarg= TRUE;
- goto again;
- }
- else {
- FAIL();
- return text;
- }
-
- default:
- return ansi_execute(vt, text);
-
- }
- }
-
- /* Action function called at last char of ANSI sequence.
- (This is only called when the char is actually seen,
- so there is no need for an 'end' parameter). */
-
- static char *
- ansi_execute(vt, text)
- VT *vt;
- char *text;
- {
- int a1= vt->args[0];
- int a2= (vt->nextarg > vt->args) ? vt->args[1] : -1;
-
- if (vt->modarg)
- return ++text; /* No semantics for those functions yet */
-
- CLIPMIN(a1, 1);
- CLIPMIN(a2, 1);
-
- switch (*text++) {
-
- case '@': vtinschars(vt, a1); break;
-
- case 'A': vtarrow(vt, WC_UP, a1); break;
-
- case 'B': vtarrow(vt, WC_DOWN, a1); break;
-
- case 'C': vtarrow(vt, WC_RIGHT, a1); break;
-
- case 'D': vtarrow(vt, WC_LEFT, a1); break;
-
- case 'H':
- case 'f': vtsetcursor(vt, vt->topterm + a1 - 1, a2-1);
- break;
-
- case 'J':
- switch (vt->args[0]) {
- case -1:
- case 0:
- vteosclear(vt, vt->topterm, 0);
- break;
- case 1:
- /* clear above cursor */
- break;
- case 2:
- vteosclear(vt, vt->cur_row, vt->cur_col);
- break;
- default:
- FAIL();
- break;
- }
- break;
-
- case 'K':
- switch (vt->args[0]) {
- case -1:
- case 0:
- vteolclear(vt, vt->cur_row, vt->cur_col);
- break;
- case 1:
- /* Clear left of cursor */
- break;
- case 2:
- vteolclear(vt, vt->cur_row, 0);
- break;
- default:
- FAIL();
- break;
- }
- break;
-
- case 'L': vtinslines(vt, a1); break;
-
- case 'M': vtdellines(vt, a1); break;
-
- case 'P': vtdelchars(vt, a1); break;
-
- case 'S': vtlinefeed(vt, a1); break;
-
- case 'T': vtrevlinefeed(vt, a1); break;
-
- case 'c': vtsendid(vt); break;
-
- case 'g': /* Tab clear */ break;
- /* 0: current col; 3: all */
-
- case 'h': vtsetoptions(vt, TRUE); break;
-
- case 'l': vtsetoptions(vt, FALSE); break;
-
- case 'm': vtsetattrlist(vt); break;
-
- case 'n': if (a1 == 6) vtsendpos(vt); break;
- /* 5: echo 'ESC [ 0 n' */
-
- case 'r': vtsetscroll(vt, vt->topterm + vt->args[0] - 1,
- vt->topterm + a2);
- break;
-
- case 'x': /* Send terminal params */ break;
-
- default: FAIL(); break;
-
- }
-
- return text;
- }
-
- /* Set/reset numbered options given in args array */
-
- static void
- vtsetoptions(vt, flag)
- VT *vt;
- bool flag; /* Set/reset */
- {
- short *a;
- for (a= vt->args; a <= vt->nextarg; ++a) {
- switch (*a) {
- case 4:
- vtsetinsert(vt, flag);
- break;
- case -1:
- /* Empty parameter, don't beep */
- break;
- default:
- FAIL();
- break;
- }
- }
- }
-
- /* Set/reset output mode attributes given in args array */
-
- static void
- vtsetattrlist(vt)
- VT *vt;
- {
- short *a;
- for (a= vt->args; a <= vt->nextarg; ++a) {
- switch (*a) {
- case -1:
- if (a == vt->args)
- vtresetattr(vt);
- break;
- case 0:
- vtresetattr(vt);
- break;
- default:
- vtsetattr(vt, *a);
- break;
- }
- }
- }
-